package com.mask.im.server.netty.handler;

import cn.hutool.json.JSONUtil;
import com.mask.im.server.netty.IMChannelCtxMap;
import com.mask.im.server.netty.enums.IMActionEnum;
import com.mask.im.server.netty.model.IMReceiveMessage;
import com.mask.im.server.netty.action.IMChatHandlerFactory;
import com.mask.token.model.TokenInfo;
import com.mask.token.util.MaskTokenParser;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.TimeUnit;


@Log4j2
@Component
@SuppressWarnings("all")
@ChannelHandler.Sharable
public class IMChatChannelHandler extends SimpleChannelInboundHandler<IMReceiveMessage> {

    @Autowired
    private IMChatHandlerFactory chatHandlerFactory;

    @Autowired
    private MaskTokenParser tokenParser;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    /**
     * 创建ChannelGroup对象存储所有连接的用户
     */
    private static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 有新消息时会调用这个方法
     *
     * @param channelHandlerContext 上下文处理器
     * @param textWebSocketFrame    文本
     * @throws Exception
     */
    @Override
    @SuppressWarnings("all")
    public void channelRead0(ChannelHandlerContext ctx, IMReceiveMessage receiveMessage) throws Exception {
        Channel channel = ctx.channel();
        try {
            log.debug("收到消息：channel={}, action={}", channel.id(), receiveMessage.getAction());
            //初始化安全上下文（设置当前登录用户）
            if (!saveSecurityContext(receiveMessage.getToken(), ctx.channel())) {
                log.info("用户未登录或登录过期");
                return;
            }
            Integer actionCode = receiveMessage.getAction();
            // 处理根节点
            IMActionEnum rootType = IMActionEnum.getByType(actionCode);
            if (null != rootType) {
                chatHandlerFactory.getHandler(rootType).handle(receiveMessage, channel);
                log.info("消息处理完成，动作类型: {}", actionCode);
            }
        } catch (Exception e) {
            log.error("消息处理异常", e);
        }
    }

    /**
     * 有新的连接建立时
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        clients.add(ctx.channel());
        log.info("新连接加入：channelId={}, 当前在线：{}", channel.id().asShortText(), clients.size());
    }

    /**
     * 不活跃时会调用这个方法
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        String channelId = channel.id().asShortText();
        try {
            // 清理用户绑定关系
            IMChannelCtxMap.deleteBindUserIdAndIdChannel(ctx.channel().id().asShortText());
            IMChannelCtxMap.deleteChannelBindUserId(ctx.channel());
            AttributeKey<Long> attributeKey = AttributeKey.valueOf("USER_ID");
            Long userId = ctx.channel().attr(attributeKey).get();
            redisTemplate.delete("im:user:node:" + userId + ":default");
            log.info("连接断开删除缓存：channelId={}, 用户id：{}", channelId, userId);
        } catch (Exception e) {
            log.error("连接断开时清理资源失败", e);
        }
        clients.remove(channel);
        log.info("连接断开：channelId={}, 当前在线：{}", channelId, clients.size());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 获取参数
        super.channelActive(ctx);
    }


    //检查客户端写心跳事件
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        Channel channel = ctx.channel();
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            if (idleStateEvent.state() == IdleState.READER_IDLE) {
                try {
                    log.warn("客户端读空闲超时：channelId={}", ctx.channel().id().asShortText());
                    IMChannelCtxMap.deleteBindUserIdAndIdChannel(ctx.channel().id().asShortText());
                    IMChannelCtxMap.deleteChannelBindUserId(ctx.channel());
                } catch (Exception e) {

                }
                clients.remove(channel);
                channel.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("通道异常：channelId={}", ctx.channel().id().asShortText(), cause);
        ctx.channel().close();
    }

    public Boolean saveSecurityContext(String token, Channel channel) {
        if (StringUtils.isBlank(token)) {
            log.warn("token为空，无法初始化安全上下文");
            return false;
        }
        try {
            AttributeKey<Long> attributeKey = AttributeKey.valueOf("USER_ID");
            boolean tokenValid = tokenParser.isTokenValid(token);
            if (!tokenValid) {
                log.warn("用户token校验 {}", tokenValid);
                return false;
            }

            Long userId = tokenParser.getUserIdDirect(token);
            channel.attr(attributeKey).set(userId);
            log.info("解析token成功，用户ID: {}", userId);
            return true;
        } catch (Exception e) {
            log.error("初始化安全上下文失败", e);
            return false;
        }
    }
}
